#pragma once

#include "Rpc_Registry.hpp"
#include "RpcRouter.hpp"
#include "../communal/Dispatcher.hpp"
#include "../client/Rpc_Client.hpp"
#include "Rpc_Topic.hpp"

namespace xu
{
    namespace server
    {
        // 注册中心服务端：只需要针对服务注册与发现请求进行处理即可
        class RegistryServer
        {
        public:
            using ptr = std::shared_ptr<RegistryServer>;

            RegistryServer(int port)
                : _dispatcher(std::make_shared<Dispatcher>()),
                  _pdmanager(std::make_shared<PDManager>())
            {
                auto cb = std::bind(&PDManager::OnServiceRequest, _pdmanager.get(), std::placeholders::_1, std::placeholders::_2);
                _dispatcher->registerHandler<ServiceRequest>(MType::REQ_SERVICE, cb);

                auto msg_cb = std::bind(&xu::Dispatcher::onMessage, _dispatcher.get(), std::placeholders::_1, std::placeholders::_2);
                _server = ModuoServerFactory::create(port);
                _server->SetMessageCallback(msg_cb);

                auto clo_cb = std::bind(&RegistryServer::onConnShutdown, this, std::placeholders::_1);
                _server->SetCloseCallback(clo_cb);
            }

            void Start()
            {
                _server->Start();
            }

        private:
            void onConnShutdown(const BaseConnection::Ptr &conn)
            {
                _pdmanager->OnConnShutdown(conn);
            }

        private:
            Dispatcher::Ptr _dispatcher;
            BaseServer::Ptr _server;
            PDManager::Ptr _pdmanager;
        };

        class RpcServer
        {
        public:
            using Ptr = std::shared_ptr<RpcServer>;

            RpcServer(const Address &addr_1, bool enableRegistry = false, const Address &addr_2 = Address())
                : _enableRegistry(enableRegistry),
                  _access_addr(addr_1),
                  _dispatcher(std::make_shared<Dispatcher>()),
                  _rpcrouter(std::make_shared<RpcRouter>())
            {
                auto cb = std::bind(&RpcRouter::RpcRequest, _rpcrouter.get(), std::placeholders::_1, std::placeholders::_2);
                _dispatcher->registerHandler<xu::RpcRequest>(xu::MType::REQ_RPC, cb);

                if (enableRegistry)
                {
                    _rclient = std::make_shared<client::RegistryClient>(addr_2.first, addr_2.second);
                    _rpcrouter->SetAddr(addr_1);
                    _rpcrouter->SetEnableRegistry(enableRegistry);
                    _rpcrouter->SetConn(_rclient->GetConn());
                    
                }

                _server = xu::ModuoServerFactory::create(addr_1.second);
                auto msg_cb = std::bind(&xu::Dispatcher::onMessage, _dispatcher.get(), std::placeholders::_1, std::placeholders::_2);
                _server->SetMessageCallback(msg_cb);
            }

            void registerMethod(const ServiceDescribe::Ptr &service)
            {
                if (_enableRegistry)
                {
                    _rclient->registryMethod(service->Method(), _access_addr);
                }

                _rpcrouter->RegisteredServe(service);
            }

            void Start()
            {
                _server->Start();
            }

        private:
            bool _enableRegistry;
            Address _access_addr;
            Dispatcher::Ptr _dispatcher;
            BaseServer::Ptr _server;
            client::RegistryClient::Ptr _rclient;
            RpcRouter::Ptr _rpcrouter;
        };

        class TopicServer
        {
        public:
            using Ptr = std::shared_ptr<TopicServer>;

            TopicServer(int port)
            : _dispatcher(std::make_shared<Dispatcher>()),
            _topicmanager(std::make_shared<TopicManager>())
            {
                auto cb = std::bind(&TopicManager::onTopicRequest, _topicmanager.get(), std::placeholders::_1, std::placeholders::_2);
                _dispatcher->registerHandler<TopicRequest>(MType::REQ_TOPIC, cb);

                auto msg_cb = std::bind(&xu::Dispatcher::onMessage, _dispatcher.get(), std::placeholders::_1, std::placeholders::_2);
                _server = ModuoServerFactory::create(port);
                _server->SetMessageCallback(msg_cb);

                auto clo_cb = std::bind(&TopicServer::onConnShutdown, this, std::placeholders::_1);
                _server->SetCloseCallback(clo_cb);
            }

            void Start()
            {
                _server->Start();
            }

        private:
            void onConnShutdown(const BaseConnection::Ptr &conn)
            {
                _topicmanager->onShutdown(conn);
            }
        private:
            TopicManager::Ptr _topicmanager;
            Dispatcher::Ptr _dispatcher;
            BaseServer::Ptr _server;
        };

    }
}